/*
 *文件作用: 测试驱动
 */

#include "leptjson.h"
#include <stdio.h>
#include <stdlib.h>  // strtod():string to double
#include <string.h>

static int test_count = 0;  //总测试次数
static int test_pass = 0;   //测试通过次数
static int main_ret = 0;    //测试程序返回值，0 for success

//================================Start:  宏====================================
//基本比较宏定义，用以比较预期结果和实际结果是否一致
//参数:
//  - equality: 预期值和实际值判断相等的方式
//  - expect: 预期值
//  - actual: 实际值
//  - format: 发生错误时, expect 和 actual 的输出格式
#define EXPECT_EQ_BASE(equality, expect, actual, format)                                                               \
    do {                                                                                                               \
        test_count++;                                                                                                  \
        if (equality) {                                                                                                \
            test_pass++;                                                                                               \
        } else {                                                                                                       \
            fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual);     \
            main_ret = 1;                                                                                              \
        }                                                                                                              \
    } while (0)

//比较预期结果和实际结果，指定以int作为格式化方式，基于基本比较宏。结果不匹配时打印错误位置和数值信息。
//参数:
//  - expect: 预期结果
//  - actual: 实际结果
#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")

//同 EXPECT_EQ_INT, 但以 double 打印 expect 和 actual。
#define EXPECT_EQ_DOUBLE(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%e")

//同上, 以 string 打印 expect 和 actual
#define EXPECT_EQ_STRING(expect_string, actual_string)                                                                 \
    do {                                                                                                               \
        EXPECT_EQ_INT(0, ((expect_string) == NULL || (actual_string) == NULL));                                        \
        EXPECT_EQ_BASE((strcmp((expect_string), (actual_string)) == 0), (expect_string), (actual_string), "%s");       \
    } while (0)

//错误码测试宏，要求出现错误时能给出预期错误码，并将节点类型强制置为 LETP_NULL
//参数:
//  - error: 预期错误码
//  - json: json字符串
#define TEST_ERROR(error, json)                                                                                        \
    do {                                                                                                               \
        lept_value v;                                                                                                  \
        v.type = LEPT_BOOLEAN;                                                                                         \
        EXPECT_EQ_INT(error, lept_parse(&v, json));                                                                    \
        EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));                                                                   \
    } while (0)

//针对 true, false, null 的value解析测试宏，以 LEPT_NULL 为原始类型
//初始化节点类型，要求解析成功，并正确修改节点类型 参数:
//  - expect_type: 预期结果类型
//  - json: json字符串
#define TEST_LITERAL(expect_type, json)                                                                                \
    do {                                                                                                               \
        lept_value v;                                                                                                  \
        v.type = LEPT_NULL;                                                                                            \
        EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json));                                                            \
        EXPECT_EQ_INT(expect_type, lept_get_type(&v));                                                                 \
        if (ISBOOLEANTYPE(&v)) {                                                                                       \
            if (ISTRUE(json)) {                                                                                        \
                EXPECT_EQ_INT(1, lept_get_boolean(&v));                                                                \
            }                                                                                                          \
        }                                                                                                              \
    } while (0)

// number 测试宏，检查解析是否成功,以及解析结果类型和解析结果数值
//参数:
//  - expect: 预期结果数字的值
//  - json: json字符串
#define TEST_NUMBER(expect, json)                                                                                      \
    do {                                                                                                               \
        lept_value v;                                                                                                  \
        EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json));                                                            \
        EXPECT_EQ_INT(LEPT_NUMBER, lept_get_type(&v));                                                                 \
        EXPECT_EQ_DOUBLE(expect, lept_get_number(&v));                                                                 \
    } while (0)

// string 测试宏
#define TEST_STRING(expect_string, json)                                                                               \
    do {                                                                                                               \
        lept_value v;                                                                                                  \
        lept_init(&v);                                                                                                 \
        EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, json));                                                            \
        EXPECT_EQ_STRING(expect_string, v.union_struct.str.string);                                                    \
    } while (0)

//================================End:  宏====================================

//=============================Start: 字面量====================================
// true, false, null 字面量解析测试集合
static void test_parse_expect_literal() {
    TEST_LITERAL(LEPT_BOOLEAN, "true");   //测试true值解析
    TEST_LITERAL(LEPT_BOOLEAN, "false");  //测试false值解析
    TEST_LITERAL(LEPT_NULL, "null");      //测试null值解析
}

//非法字面量解析测试集合
static void test_parse_invalid_literal() {
    TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "false f");  //测试多值输入
    TEST_ERROR(LEPT_PARSE_EXPECT_VALUE, " \t\n\r");       //测试无值输入
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "monday");       //测试非法输入
}

//字面量解析集合
static void test_parse_literal() {
    test_parse_expect_literal();   //测试合法字面量
    test_parse_invalid_literal();  //测试非法字面量
}
//===========================End: 字面量===============================

//===========================Start:  数字==============================
// number 解析测试集合
static void test_parse_expect_number() {
    TEST_NUMBER(0.0, "0");
    TEST_NUMBER(0.0, "-0");
    TEST_NUMBER(0.0, "-0.0");
    TEST_NUMBER(1.0, "1");
    TEST_NUMBER(-1.0, "-1");
    TEST_NUMBER(1.5, "1.5");
    TEST_NUMBER(-1.5, "-1.5");
    TEST_NUMBER(3.1416, "3.1416");
    TEST_NUMBER(1E10, "1E10");
    TEST_NUMBER(1e10, "1e10");
    TEST_NUMBER(1E+10, "1E+10");
    TEST_NUMBER(1E-10, "1E-10");
    TEST_NUMBER(-1E10, "-1E10");
    TEST_NUMBER(-1e10, "-1e10");
    TEST_NUMBER(-1E+10, "-1E+10");
    TEST_NUMBER(-1E-10, "-1E-10");
    TEST_NUMBER(1.234E+10, "1.234E+10");
    TEST_NUMBER(1.234E-10, "1.234E-10");
    TEST_NUMBER(0.0, "1e-10000"); /* must underflow */

    TEST_NUMBER(1.0000000000000002, "1.0000000000000002");            // the smallest number > 1
    TEST_NUMBER(4.9406564584124654e-324, "4.9406564584124654e-324");  // Min. subnormal positive double
    TEST_NUMBER(-4.9406564584124654e-324, "-4.9406564584124654e-324");
    TEST_NUMBER(2.2250738585072009e-308, "2.2250738585072009e-308");    // Max. subnormal double
    TEST_NUMBER(-2.2250738585072009e-308, "-2.2250738585072009e-308");  //
    TEST_NUMBER(2.2250738585072014e-308, "2.2250738585072014e-308");    // Min. normal positive double
    TEST_NUMBER(-2.2250738585072014e-308, "-2.2250738585072014e-308");
    TEST_NUMBER(1.7976931348623157e308, "1.7976931348623157e308");  // Max. Double
    TEST_NUMBER(-1.7976931348623157e308, "-1.7976931348623157e308");
}

//测试非法数字
static void test_parse_invalid_number() {
    /* invalid number */
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+0");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+1");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, ".123");  // at least one digit before '.'
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "1.");    // at least one digit after '.'
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "INF");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "inf");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "NAN");
    TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "nan");
}

static void test_parse_number() {
    test_parse_expect_number();   //测试合法数字
    test_parse_invalid_number();  //测试非法数字
}
//===========================End:  数字==============================

static void test_access_string() {
    lept_value v;
    lept_init(&v);
    lept_set_string(&v, "true", 4);
    EXPECT_EQ_STRING("true", lept_get_string(&v));
}

static void test_parse_expect_string() {
    TEST_STRING("normal characters", "\"normal characters\"");    // normal characters
    TEST_STRING("quotation mark\"", "\"quotation mark\\\"\"");    // quotation mark
    TEST_STRING("reverse solidus\\", "\"reverse solidus\\\\\"");  // reverse solidus
    TEST_STRING("solidus\/", "\"solidus\\\/\"");                  // solidus
    TEST_STRING("backspace\b", "\"backspace\\b\"");               // backspace
    TEST_STRING("form feed\f", "\"form feed\\f\"");               // form feed
    TEST_STRING("line feed\n", "\"line feed\\n\"");               // line feed
    TEST_STRING("carriage return\r", "\"carriage return\\r\"");   // carriage return
    TEST_STRING("tab\t", "\"tab\\t\"");                           // tab
}
static void test_parse_invalid_string() {
    TEST_ERROR(LEPT_PARSE_INVALID_STRING_ESCAPE, "\"invalid_escape\\p\"");  // invalid escape \p
    TEST_ERROR(LEPT_PARSE_MISS_QUOTATION_MARK, "\"miss_quotation_mark");    // miss quotation mark
}

static void test_parse_string() {}

//解析测试
static void test_parse() {
#if 1
#    if 0
    test_parse_expect_literal();  //解析value字面量: true, false, null
    test_parse_invalid_literal();  //解析非法字面量
#    endif
#    if 0
    test_parse_expect_number();
    test_parse_invalid_number();
#    endif
#    if 1
    test_parse_expect_string();
    test_parse_invalid_string();
#    endif
#endif
}

int main(void) {
    test_parse();  //测试解析
    if (test_count == 0) {
        printf("No test.\n");
        return main_ret;
    }
    //打印通过次数、总测试次数、通过率
    printf("%d / %d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count);
    return main_ret;
}